<!DOCTYPE html>
<html lang="en">

<head>     
    <title>clip-path可视化</title>
    <meta charset="UTF-8" />     
    <meta id="viewport" content="width=device-width, initial-scale=1.0" />
    <link href="./clip-path.css" rel="stylesheet" />
</head>

<body class="page-container">
    <!-- 工作区 -->
    <main id="play-ground-ele" class="play-ground">
        <!-- 蒙层面板 -->
        <section class="shadow-board"></section>
        <!-- 裁剪面板 -->
        <section id="clip-board-ele" class="clip-board">
        </section>
        <!-- 四个拖拽点 -->
        <section id="points-ele" class="points">
            <div id="point1-ele" class="point"></div>
            <div id="point2-ele" class="point"></div>
            <div id="point3-ele" class="point"></div>
            <div id="point4-ele" class="point"></div>
        </section>
    </main>
    <!-- css代码区域 -->
    <footer class="show-css-code">
        <pre id="show-code-ele" class="code-area"></pre>
        <button id="copy-ele">复制</button>
        <div id="toast-ele" class="toast">复制成功</div>
    </footer>
</body>

<script>

    // 裁剪正方形的边长
    const shadowBoardSquare = 280;

    // 拖拽工作区
    const playGroundEle = document.querySelector('#play-ground-ele');
    // offsetLeft,offsetTop是相对于body元素的左上角偏移
    const { offsetLeft, offsetTop, clientWidth } = playGroundEle;
    // 拖拽工作区和拖拽蒙层之间的偏移
    const boxOffset = (clientWidth - shadowBoardSquare) / 2;


    // 拖拽点容器
    const pointsEle = document.querySelector('#points-ele');
    // 裁剪板
    const clipboardEle = document.querySelector('#clip-board-ele');

    // 展示css代码
    const showCodeEle = document.querySelector('#show-code-ele');

    // 四个拖拽点的初始坐标(百分比)
    let coords = [
        { id: 'point1-ele', axis: { xPer: 20, yPer: 0 } },
        { id: 'point2-ele', axis: { xPer: 80, yPer: 0 } },
        { id: 'point3-ele', axis: { xPer: 100, yPer: 100 } },
        { id: 'point4-ele', axis: { xPer: 0, yPer: 100 } }
    ];

    const pointIds = coords.map((item) => item.id);

    // 裁剪图片初始化
    clipPicInit();

    function clipPicInit() {
        coords.forEach(({ id, axis }, index) => {
            const ele = document.querySelector(`#${id}`);
            const offsetX = shadowBoardSquare * axis.xPer / 100;
            const offsetY = shadowBoardSquare * axis.yPer / 100;
            setEleAttr(index, ele, { offsetX, offsetY }, false);
        });
    }

    // 鼠标左键按下时 清除mousemove事件和拖拽裁剪点动态样式 
    pointsEle.addEventListener('mousedown', function (e) {
        // 至关重要,禁止浏览器默认行为,不然mouseup事件有时不响应,导致无法清除mousemove事件
        e.preventDefault();

        // 只监听鼠标左键按下事件
        if (e.button !== 0) return false;


        // 为了提高事件绑定性能,采用的是事件委托的写法,所以要判断触发事件的元素
        if (pointIds.includes(e.target.id)) {
            e.target.classList.add('is-dragging');
            document.addEventListener('mousemove', moveCb);
        }
    });

    // 鼠标左键抬起时 清除mousemove事件和拖拽裁剪点动态样式
    document.addEventListener('mouseup', function (e) {
        coords.forEach(({ id }) => {
            document.querySelector(`#${id}`).classList.remove('is-dragging');
        })
        document.removeEventListener('mousemove', moveCb);
    });


    // 鼠标移动回调函数
    const moveCb = (e) => {
        const ele = document.querySelector('.is-dragging');

        let { offsetX, offsetY } = extractTranslateOffset(ele);
        const { clientX, clientY, movementX, movementY } = e;
        offsetX += movementX; //距上次鼠标位置的X偏移量
        offsetY += movementY; //距上次鼠标位置的X偏移量
        // console.log({ offsetX, offsetY });

        // 防止拖拽点移动过快,飞出容器

        // 超出左侧边界
        if (clientX < (offsetLeft + boxOffset)) {
            offsetX = 0;
        }
        // 超出右侧边界
        else if (clientX >= (offsetLeft + shadowBoardSquare + boxOffset)) {
            offsetX = shadowBoardSquare;
        }

        // 超出上侧边界
        if (clientY < (offsetTop + boxOffset)) {
            offsetY = 0;
        }
        // 超出下侧边界
        else if (clientY > (offsetTop + shadowBoardSquare + boxOffset)) {
            offsetY = shadowBoardSquare;
        }

        const index = pointIds.findIndex(id => id === ele.id);
        setEleAttr(index, ele, { offsetX, offsetY });

    };
    /**
     * 设置元素属性
     * index-拖动的元素序号
     * ele-拖拽的元素
     * offsetX, offsetY 鼠标偏移量
     * isMove 是否正在拖动裁剪点
     * */
    function setEleAttr(index, ele, { offsetX, offsetY }, isMove = true) {

        // 裁剪图片设置属性值是百分比
        coords[index].axis.xPer = toPercent(offsetX);
        coords[index].axis.yPer = toPercent(offsetY);

        // 图片裁剪代码是拼接属性值文本
        const points = coords.map((item, index) => `${coords[index].axis.xPer}% ${coords[index].axis.yPer}%`);
        // 展示代码是拼接四个code标签
        const showPoints = coords.map((item, pointIndex) => `<code class="code-item ${isMove && pointIndex === index && 'changing'}">${coords[pointIndex].axis.xPer}% ${coords[pointIndex].axis.yPer}%</code>`);


        // 设置拖拽点的偏移--注意translate后面不能加分号,加了设置的属性会不生效
        ele.style.transform = `translate(${offsetX}px,${offsetY}px)`;
        // 设置图片裁剪属性
        clipboardEle.style.cssText = `clip-path: polygon(${points.join(',')});`;
        // 设置展示代码
        showCodeEle.innerHTML = `clip-path: polygon(${showPoints.join(',')});`;
    }

    /**
     * 将transform:translate(x,y)中的x,y偏移量提取出来
     * 注意 用ele.style.cssText获取不到将transform属性值,要用window.getComputedStyle函数才行
     * */
    function extractTranslateOffset(ele) {
        // 获取位移矩阵
        const matrix = window.getComputedStyle(ele, null).transform.split(',');

        // console.log(matrix);
        // matrix的值是这样的:['matrix(1', ' 0', ' 0', ' 1', ' 56', ' 0)'];
        // 后面两个值是x和y的偏移量
        let offsetX = parseFloat(matrix[4]);
        // parseFloat可以将形如'56)'这样的字符串转换成数字56
        let offsetY = parseFloat(matrix[5]);
        return { offsetX, offsetY };
    }

    /**
     * 将整数转换成百分比
     * num: css像素值
     * */
    function toPercent(num) {
        return (parseFloat(num / shadowBoardSquare) * 100).toFixed(0);
    }

    // 复制裁剪图片属性值
    document.querySelector('#copy-ele').addEventListener('click', copy);
    function copy() {
        var copyInput = document.createElement("input");
        var text = clipboardEle.style.cssText;
        copyInput.setAttribute("value", text);
        document.body.appendChild(copyInput);
        copyInput.select();
        document.execCommand("copy",true);
        document.body.removeChild(copyInput);

        const toastEle=document.querySelector('#toast-ele'); 
        toastEle.classList.add('show');
        setTimeout(()=>{
            toastEle.classList.remove('show'); 
        },1000);
        
        // alert('复制成功！');
    }

    // 防止鼠标移出边界,仍然可以拖动剪裁点
    // pointsEle.addEventListener('mouseleave', function (e) {
    //     // e.preventDefault();

    //     // coords.forEach(({ id }) => {
    //     //     document.querySelector(`#${id}`).classList.remove('is-dragging');
    //     // });
    //     trigger(document, 'mouseup');
    // });
    // 手动派发事件
    // function trigger(ele, eventName) {
    //     const event = new Event(eventName);
    //     ele?.dispatchEvent(event);
    // }
    // document.addEventListener('mousemove', moveCb);
</script>

</html>